#Flask：是 Flask 框架的核心类，用于创建 Flask 应用程序实例
#render_template：用于渲染 HTML 模板
#request：处理客户端发送的请求，包括获取请求参数、文件上传
#redirect：用于重定向到另一个 URL；
#url_for：根据视图函数的名称生成 URL，常用于在代码中动态生成链接
#flash：用于在页面之间传递一次性消息，通常用于显示操作的成功或失败消息
#send_from_directory：从指定目录发送文件；abort：用于中止请求并返回错误响应；jsonify：将 Python 对象转换为 JSON 格式的响应
#send_file：发送文件作为响应
from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory, abort, jsonify, send_file
#login_user：用于登录用户，将用户信息存储在会话中；login_required：是一个装饰器，用于保护需要登录才能访问的视图函数
#logout_user：用于注销用户；current_user：表示当前登录的用户
from flask_login import login_user, login_required, logout_user, current_user
#用于与操作系统进行交互，例如文件和目录操作
import os
from werkzeug.utils import secure_filename
import time
from datetime import datetime
from extensions import db, login_manager, csrf
#从 models 模块中导入各种数据模型类，这些类通常用于与数据库表进行映射，使用 SQLAlchemy 定义表结构和操作
from models import User, Evaluation, Scholarship, Outstanding, AcademicRecord, MoralRecord, PhysicalRecord, AbilityRecord, LaborRecord, ScholarshipApplication
#openpyxl 是一个用于操作 Excel 文件的库，Workbook 是用于创建新的 Excel 工作簿的类
from openpyxl import Workbook
#BytesIO 是一个内存中的二进制流对象，可用于存储文件数据
from io import BytesIO

# 添加允许的文件类型
ALLOWED_EXTENSIONS = {'pdf', 'doc', 'docx', 'jpg', 'jpeg', 'png'}

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def create_app():
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'your-secret-key'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///evaluation.db'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    # 初始化扩展
    db.init_app(app)
    login_manager.init_app(app)
    csrf.init_app(app)

    login_manager.login_view = 'login'

    # 设置允许上传的文件类型和上传文件夹
    UPLOAD_FOLDER = 'uploads'
    if not os.path.exists(UPLOAD_FOLDER):
        os.makedirs(UPLOAD_FOLDER)
    
    app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

    return app

app = create_app()

# 用户加载函数
@login_manager.user_loader
def load_user(user_id):
    return db.session.get(User, int(user_id))

# 路由
@app.route('/')
def index():
    if current_user.is_authenticated:
        return redirect(url_for('dashboard'))
    return redirect(url_for('login'))

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        user = User.query.filter_by(username=username).first()
        
        if user and user.password == password:
            login_user(user)
            return redirect(url_for('dashboard'))
        
        flash('用户名或密码错误')
    return render_template('login.html')

@app.route('/dashboard')
@login_required
def dashboard():
    if current_user.role == 'student':
        # 获取最新的已通过成绩记录
        academic_record = AcademicRecord.query.filter_by(
            student_id=current_user.id,
            status='approved'
        ).order_by(
            AcademicRecord.submit_time.desc()
        ).first()
        
        moral_record = MoralRecord.query.filter_by(
            student_id=current_user.id,
            status='approved'
        ).order_by(
            MoralRecord.submit_time.desc()
        ).first()
        
        physical_record = PhysicalRecord.query.filter_by(
            student_id=current_user.id,
            status='approved'
        ).order_by(
            PhysicalRecord.submit_time.desc()
        ).first()
        
        ability_record = AbilityRecord.query.filter_by(
            student_id=current_user.id,
            status='approved'
        ).order_by(
            AbilityRecord.submit_time.desc()
        ).first()
        
        labor_record = LaborRecord.query.filter_by(
            student_id=current_user.id,
            status='approved'
        ).order_by(
            LaborRecord.submit_time.desc()
        ).first()
        
        # 获取或创建综合评定记录
        evaluation = Evaluation.query.filter_by(
            student_id=current_user.id,
            semester=current_semester()
        ).first()
        
        if not evaluation:
            evaluation = Evaluation(
                student_id=current_user.id,
                class_name=current_user.class_name,
                semester=current_semester(),
                academic_score=academic_record.academic_score if academic_record else 0,
                moral_score=moral_record.total_score if moral_record else 0,
                physical_score=physical_record.physical_score if physical_record else 0,
                ability_score=ability_record.total_score if ability_record else 0,
                labor_score=labor_record.labor_score if labor_record else 0
            )
            db.session.add(evaluation)
        else:
            # 更新现有评定记录
            evaluation.academic_score = academic_record.academic_score if academic_record else 0
            evaluation.moral_score = moral_record.total_score if moral_record else 0
            evaluation.physical_score = physical_record.physical_score if physical_record else 0
            evaluation.ability_score = ability_record.total_score if ability_record else 0
            evaluation.labor_score = labor_record.labor_score if labor_record else 0
        
        # 计算总分（修改计算方式）
        # 德育素质分*25% + 智育成绩分*50%*25 + 体育素质分*5% + 能力素质分*15% + 劳育素质分*5%
        evaluation.total_score = (
            (evaluation.moral_score or 0) * 0.25 +    # 德育素质 25%
            (evaluation.academic_score or 0) * 0.50 * 25 +  # 智育成绩 50%
            (evaluation.physical_score or 0) * 0.05 +  # 体育素质 5%
            (evaluation.ability_score or 0) * 0.15 +   # 能力素质 15%
            (evaluation.labor_score or 0) * 0.05       # 劳育素质 5%
        )
        
        db.session.commit()
        
        # 获取所有评定记录用于显示
        evaluations = Evaluation.query.filter_by(
            student_id=current_user.id
        ).order_by(
            Evaluation.semester.desc()
        ).all()
        
        # 获取所有已通过的成绩记录用于详细显示
        academic_records = AcademicRecord.query.filter_by(
            student_id=current_user.id,
            status='approved'
        ).order_by(AcademicRecord.semester.desc()).all()
        
        moral_records = MoralRecord.query.filter_by(
            student_id=current_user.id,
            status='approved'
        ).order_by(MoralRecord.semester.desc()).all()
        
        physical_records = PhysicalRecord.query.filter_by(
            student_id=current_user.id,
            status='approved'
        ).order_by(PhysicalRecord.semester.desc()).all()
        
        ability_records = AbilityRecord.query.filter_by(
            student_id=current_user.id,
            status='approved'
        ).order_by(AbilityRecord.semester.desc()).all()
        
        labor_records = LaborRecord.query.filter_by(
            student_id=current_user.id,
            status='approved'
        ).order_by(LaborRecord.semester.desc()).all()
        
        return render_template('dashboard.html', 
                             evaluations=evaluations,
                             academic_records=academic_records,
                             moral_records=moral_records,
                             physical_records=physical_records,
                             ability_records=ability_records,
                             labor_records=labor_records)
    
    elif current_user.role == 'teacher':
        # 教师视图
        # 获取本班级所有学生的所有类型成绩（不再过滤状态）
        academic_records = AcademicRecord.query.join(User).filter(
            User.class_name == current_user.class_name
        ).all()
        
        moral_records = MoralRecord.query.join(User).filter(
            User.class_name == current_user.class_name
        ).all()
        
        physical_records = PhysicalRecord.query.join(User).filter(
            User.class_name == current_user.class_name
        ).all()
        
        ability_records = AbilityRecord.query.join(User).filter(
            User.class_name == current_user.class_name
        ).all()
        
        labor_records = LaborRecord.query.join(User).filter(
            User.class_name == current_user.class_name
        ).all()
        
        # 获取班级所有学生的综合评定
        class_evaluations = Evaluation.query.join(User).filter(
            User.class_name == current_user.class_name
        ).order_by(
            User.username,
            Evaluation.semester.desc()
        ).all()
        
        # 获取班级学生列表
        students = User.query.filter_by(
            class_name=current_user.class_name,
            role='student'
        ).all()
        
        return render_template('dashboard.html',
                             students=students,
                             class_evaluations=class_evaluations,
                             academic_records=academic_records,
                             moral_records=moral_records,
                             physical_records=physical_records,
                             ability_records=ability_records,
                             labor_records=labor_records)
    
    return render_template('dashboard.html')

@app.route('/academic', methods=['GET', 'POST'])
@login_required
def academic():
    if current_user.role == 'student':
        # 学生只能看到自己的成绩记录
        academic_records = AcademicRecord.query.filter_by(student_id=current_user.id).all()
    elif current_user.role == 'teacher':
        # 教师只能看到自己班级的学生成绩
        academic_records = AcademicRecord.query.join(User).filter(
            User.class_name == current_user.class_name
        ).all()
    else:
        # 管理员可以看到所有记录
        academic_records = AcademicRecord.query.all()
    
    return render_template('academic.html', academic_records=academic_records)

@app.route('/moral', methods=['GET'])
@login_required
def moral():
    if current_user.role == 'student':
        # 学生只能看到自己的记录
        moral_records = MoralRecord.query.filter_by(student_id=current_user.id).all()
    elif current_user.role == 'teacher':
        # 教师只能看到自己班级的记录
        moral_records = MoralRecord.query.join(User).filter(
            User.class_name == current_user.class_name
        ).all()
    else:
        # 管理员可以看到所有记录
        moral_records = MoralRecord.query.all()
    
    return render_template('moral.html', moral_records=moral_records)

@app.route('/physical', methods=['GET'])
@login_required
def physical():
    if current_user.role == 'student':
        # 学生只能看到自己的记录
        physical_records = PhysicalRecord.query.filter_by(student_id=current_user.id).all()
    elif current_user.role == 'teacher':
        # 教师只能看到自己班级的记录
        physical_records = PhysicalRecord.query.join(User).filter(
            User.class_name == current_user.class_name
        ).all()
    else:
        # 管理员可以看到所有记录
        physical_records = PhysicalRecord.query.all()
    
    return render_template('physical.html', physical_records=physical_records)

@app.route('/ability', methods=['GET'])
@login_required
def ability():
    if current_user.role == 'student':
        # 学生只能看到自己的记录
        ability_records = AbilityRecord.query.filter_by(student_id=current_user.id).all()
    elif current_user.role == 'teacher':
        # 教师只能看到自己班级的记录
        ability_records = AbilityRecord.query.join(User).filter(
            User.class_name == current_user.class_name
        ).all()
    else:
        # 管理员可以看到所有记录
        ability_records = AbilityRecord.query.all()
    
    return render_template('ability.html', ability_records=ability_records)

@app.route('/submit_ability', methods=['POST'])
@login_required
def submit_ability():
    if current_user.role != 'student':
        flash('只有学生可以提交成绩', 'error')
        return redirect(url_for('ability'))
    
    try:
        semester = request.form['semester']
        
        # 处理学术科技能项目
        academic_items = []
        academic_score = 0
        academic_item_list = request.form.getlist('academic_items[]')
        academic_score_list = request.form.getlist('academic_scores[]')
        academic_other_list = request.form.getlist('academic_other[]')
        
        for item, score, other in zip(academic_item_list, academic_score_list, academic_other_list):
            if item and score:
                score = float(score)
                item_data = {
                    'item': item,
                    'score': score
                }
                if item == 'other':
                    item_data['other_content'] = other
                academic_items.append(item_data)
                academic_score += score
        
        # 验证学术科技能力分不超过50分
        if academic_score > 50:
            flash('学术科技能力分不能超过50分', 'error')
            return redirect(url_for('ability'))
        
        # 处理社会实践能力项目
        social_items = []
        social_score = 0
        social_item_list = request.form.getlist('social_items[]')
        social_score_list = request.form.getlist('social_scores[]')
        social_other_list = request.form.getlist('social_other[]')
        
        for item, score, other in zip(social_item_list, social_score_list, social_other_list):
            if item and score:
                score = float(score)
                item_data = {
                    'item': item,
                    'score': score
                }
                if item == 'other':
                    item_data['other_content'] = other
                social_items.append(item_data)
                social_score += score
        
        # 验证社会实践能力分不超过20分
        if social_score > 20:
            flash('社会实践能力分不能超过20分', 'error')
            return redirect(url_for('ability'))
        
        # 处理综合技能项目
        skill_items = []
        skill_score = 0
        skill_item_list = request.form.getlist('skill_items[]')
        skill_score_list = request.form.getlist('skill_scores[]')
        skill_other_list = request.form.getlist('skill_other[]')
        
        for item, score, other in zip(skill_item_list, skill_score_list, skill_other_list):
            if item and score:
                score = float(score)
                item_data = {
                    'item': item,
                    'score': score
                }
                if item == 'other':
                    item_data['other_content'] = other
                skill_items.append(item_data)
                skill_score += score
        
        # 验证综合技能分不超过30分
        if skill_score > 30:
            flash('综合技能分不能超过30分', 'error')
            return redirect(url_for('ability'))
        
        # 计算总分
        total_score = academic_score + social_score + skill_score
        
        # 处理文件上传（选填）
        proof_file = None
        if 'proof_file' in request.files:
            file = request.files['proof_file']
            if file and file.filename != '' and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                unique_filename = f"ability_{current_user.username}_{int(time.time())}_{filename}"
                file_path = os.path.join(UPLOAD_FOLDER, unique_filename)
                file.save(file_path)
                proof_file = unique_filename
        
        # 创建新记录
        new_record = AbilityRecord(
            student_id=current_user.id,
            class_name=current_user.class_name,
            semester=semester,
            academic_items=academic_items,
            academic_score=academic_score,
            social_items=social_items,
            social_score=social_score,
            skill_items=skill_items,
            skill_score=skill_score,
            total_score=total_score,
            proof_file=proof_file,
            status='pending',
            submit_time=datetime.now()
        )
        
        db.session.add(new_record)
        db.session.commit()
        
        flash('能力素质评分提交成功，等待审核', 'success')
        return redirect(url_for('ability'))
        
    except Exception as e:
        print(f"Error submitting ability score: {str(e)}")  # 调试信息
        flash('提交失败，请稍后重试', 'error')
        return redirect(url_for('ability'))

# 添加审核路由
@app.route('/approve_ability/<int:record_id>', methods=['POST'])
@login_required
def approve_ability(record_id):
    try:
        if current_user.role != 'teacher':
            return jsonify({'success': False, 'message': '权限不足'}), 403
            
        record = AbilityRecord.query.get_or_404(record_id)
        
        if record.class_name != current_user.class_name:
            return jsonify({'success': False, 'message': '不能审核其他班级的成绩'}), 403
        
        record.status = 'approved'
        record.update_time = datetime.now()  # 添加更新时间
        db.session.commit()
        return jsonify({'success': True, 'message': '审核通过成功'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/reject_ability/<int:record_id>', methods=['POST'])
@login_required
def reject_ability(record_id):
    try:
        if current_user.role != 'teacher':
            return jsonify({'success': False, 'message': '权限不足'}), 403
            
        record = AbilityRecord.query.get_or_404(record_id)
        
        if record.class_name != current_user.class_name:
            return jsonify({'success': False, 'message': '不能审核其他班级的成绩'}), 403
        
        record.status = 'rejected'
        db.session.commit()
        return jsonify({'success': True, 'message': '驳回成功'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'message': str(e)}), 500

# 添加证明材料下载路由
@app.route('/download_ability_proof/<int:file_id>')
@login_required
def download_ability_proof(file_id):
    record = AbilityRecord.query.get_or_404(file_id)
    
    if current_user.role != 'teacher' and current_user.id != record.student_id:
        abort(403)
    
    if record.proof_file:
        return send_from_directory(UPLOAD_FOLDER, record.proof_file)
    abort(404)

@app.route('/labor', methods=['GET'])
@login_required
def labor():
    if current_user.role == 'student':
        # 学生只能看到自己的记录
        labor_records = LaborRecord.query.filter_by(student_id=current_user.id).all()
    elif current_user.role == 'teacher':
        # 教师只能看到自己班级的记录
        labor_records = LaborRecord.query.join(User).filter(
            User.class_name == current_user.class_name
        ).all()
    else:
        # 管理员可以看到所有记录
        labor_records = LaborRecord.query.all()
    
    return render_template('labor.html', labor_records=labor_records)

@app.route('/submit_labor', methods=['POST'])
@login_required
def submit_labor():
    if current_user.role != 'student':
        flash('只有学生可以提交成绩', 'error')
        return redirect(url_for('labor'))
    
    try:
        semester = request.form['semester']
        labor_type = request.form['labor_type']
        labor_score = float(request.form['labor_score'])
        
        # 修改劳育类型和对应分数的验证
        expected_scores = {
            '第一学年满16学时': 100,
            '第一学年达6-15学时': 80,
            '第一学年低于6学时': 0,
            '第二（三）学年满32学时': 100,
            '第二（三）学年未满32学时': 0,
            '入伍免修': 100
        }
        
        # 验证劳育类型
        if labor_type not in expected_scores:
            flash('无效的劳育类型', 'error')
            return redirect(url_for('labor'))
        
        # 验证成绩是否与类型匹配
        if labor_score != expected_scores[labor_type]:
            flash(f'成绩必须为{expected_scores[labor_type]}分', 'error')
            return redirect(url_for('labor'))
        
        # 处理文件上传（选填）
        proof_file = None
        if 'proof_file' in request.files:
            file = request.files['proof_file']
            if file and file.filename != '' and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                unique_filename = f"labor_{current_user.username}_{int(time.time())}_{filename}"
                file_path = os.path.join(UPLOAD_FOLDER, unique_filename)
                file.save(file_path)
                proof_file = unique_filename
        
        # 创建新记录
        new_record = LaborRecord(
            student_id=current_user.id,
            class_name=current_user.class_name,
            semester=semester,
            labor_type=labor_type,
            labor_score=labor_score,
            proof_file=proof_file,
            status='pending',
            submit_time=datetime.now()
        )
        
        db.session.add(new_record)
        db.session.commit()
        
        flash('劳育成绩提交成功，等待审核', 'success')
        return redirect(url_for('labor'))
        
    except Exception as e:
        print(f"Error submitting labor score: {str(e)}")
        flash('提交失败，请稍后重试', 'error')
        return redirect(url_for('labor'))

# 添加审核和下载路由
@app.route('/approve_labor/<int:record_id>', methods=['POST'])
@login_required
def approve_labor(record_id):
    try:
        if current_user.role != 'teacher':
            return jsonify({'success': False, 'message': '权限不足'}), 403
            
        record = LaborRecord.query.get_or_404(record_id)
        
        if record.class_name != current_user.class_name:
            return jsonify({'success': False, 'message': '不能审核其他班级的成绩'}), 403
        
        record.status = 'approved'
        record.update_time = datetime.now()  # 添加更新时间
        db.session.commit()
        return jsonify({'success': True, 'message': '审核通过成功'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/reject_labor/<int:record_id>', methods=['POST'])
@login_required
def reject_labor(record_id):
    try:
        if current_user.role != 'teacher':
            return jsonify({'success': False, 'message': '权限不足'}), 403
            
        record = LaborRecord.query.get_or_404(record_id)
        
        if record.class_name != current_user.class_name:
            return jsonify({'success': False, 'message': '不能审核其他班级的成绩'}), 403
        
        record.status = 'rejected'
        db.session.commit()
        return jsonify({'success': True, 'message': '驳回成功'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/download_labor_proof/<int:file_id>')
@login_required
def download_labor_proof(file_id):
    record = LaborRecord.query.get_or_404(file_id)
    
    if current_user.role != 'teacher' and current_user.id != record.student_id:
        abort(403)
    
    if record.proof_file:
        return send_from_directory(UPLOAD_FOLDER, record.proof_file)
    abort(404)

@app.route('/scholarship', methods=['GET'])
@login_required
def scholarship():
    if current_user.role == 'student':
        # 学生只能看到自己的申请记录
        scholarship_records = ScholarshipApplication.query.filter_by(
            user_id=current_user.id
        ).order_by(
            ScholarshipApplication.submit_time.desc()
        ).all()
    elif current_user.role == 'teacher':
        # 教师能看到自己班级所有学生的申请记录
        scholarship_records = ScholarshipApplication.query.filter_by(
            class_name=current_user.class_name  # 直接使用class_name字段过滤
        ).order_by(
            ScholarshipApplication.submit_time.desc()
        ).all()
    else:
        # 管理员可以看到所有记录
        scholarship_records = ScholarshipApplication.query.order_by(
            ScholarshipApplication.submit_time.desc()
        ).all()
    
    return render_template('scholarship.html', 
                         scholarship_records=scholarship_records,
                         current_user=current_user)

@app.route('/submit_scholarship', methods=['POST'])
@login_required
def submit_scholarship():
    try:
        # 获取当前学生的班级信息
        student = User.query.get(current_user.id)
        if not student:
            flash('用户信息获取失败', 'error')
            return redirect(url_for('scholarship'))

        # 获取基本信息
        basic_info = {
            'real_name': request.form.get('real_name'),
            'username': request.form.get('username'),
            'gender': request.form.get('gender'),
            'birth_date': request.form.get('birth_date'),
            'ethnicity': request.form.get('ethnicity'),
            'id_number': request.form.get('id_number'),
            'hometown': request.form.get('hometown'),
            'household_type': request.form.get('household_type'),
            'political_status': request.form.get('political_status'),
            'college': request.form.get('college'),
            'major': request.form.get('major'),
            'class_name': student.class_name  # 使用学生的实际班级
        }

        # 获取学习情况
        study_info = {
            'required_courses': request.form.get('required_courses'),
            'pass_courses': request.form.get('pass_courses'),
            'total_students': request.form.get('total_students'),
            'rank': request.form.get('rank'),
            'ranking_type': request.form.get('ranking_type'),
            'rank_scope': request.form.get('rank_scope'),
            'rank_description': request.form.get('rank_description')
        }

        # 获取奖学金信息
        departments = request.form.getlist('departments[]')
        amounts = request.form.getlist('amounts[]')
        periods = request.form.getlist('periods[]')
        
        scholarship_info = []
        for i in range(len(departments)):
            scholarship_info.append({
                'department': departments[i],
                'amount': amounts[i],
                'period': periods[i]
            })

        # 获取获奖情况
        award_names = request.form.getlist('award_names[]')
        award_types = request.form.getlist('award_type[]')
        award_dates = request.form.getlist('award_date[]')
        award_years = request.form.getlist('award_year[]')
        
        awards_info = []
        for i in range(len(award_names)):
            if award_names[i]:  # 只添加非空的奖项
                awards_info.append({
                    'name': award_names[i],
                    'type': award_types[i],
                    'date': award_dates[i],
                    'year': award_years[i]
                })

        # 处理附件上传
        files = request.files.getlist('attachments[]')
        saved_files = []
        
        for file in files:
            if file and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
                file.save(file_path)
                saved_files.append(filename)

        # 创建奖学金申请记录
        application = ScholarshipApplication(
            user_id=current_user.id,
            basic_info=basic_info,
            study_info=study_info,
            scholarship_info=scholarship_info,
            awards_info=awards_info,
            application_reason=request.form.get('application_reason'),
            attachments=saved_files,
            status='pending',
            class_name=student.class_name  # 添加班级息
        )

        db.session.add(application)
        db.session.commit()

        flash('奖学金申请提交成功！', 'success')
        return redirect(url_for('scholarship'))

    except Exception as e:
        db.session.rollback()
        print(f"Error submitting scholarship application: {str(e)}")
        flash('提交失败，请稍后重试', 'error')
        return redirect(url_for('scholarship'))

@app.route('/approve_scholarship/<int:record_id>', methods=['POST'])
@login_required
def approve_scholarship(record_id):
    try:
        if current_user.role != 'teacher':
            return jsonify({'success': False, 'message': '权限不足'}), 403
            
        record = ScholarshipApplication.query.get_or_404(record_id)
        student = User.query.get(record.user_id)
        
        if student.class_name != current_user.class_name:
            return jsonify({'success': False, 'message': '不能审核其他班级的申请'}), 403
        
        record.status = 'approved'
        record.update_time = datetime.now()
        db.session.commit()
        return jsonify({'success': True, 'message': '审核通过成功'})
    except Exception as e:
        db.session.rollback()
        print(f"Error approving scholarship: {str(e)}")  # 添加错误日志
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/reject_scholarship/<int:record_id>', methods=['POST'])
@login_required
def reject_scholarship(record_id):
    try:
        if current_user.role != 'teacher':
            return jsonify({'success': False, 'message': '权限不足'}), 403
            
        record = ScholarshipApplication.query.get_or_404(record_id)
        student = User.query.get(record.user_id)
        
        if student.class_name != current_user.class_name:
            return jsonify({'success': False, 'message': '不能审核其他班级的申请'}), 403
        
        record.status = 'rejected'
        record.update_time = datetime.now()
        db.session.commit()
        return jsonify({'success': True, 'message': '驳回成功'})
    except Exception as e:
        db.session.rollback()
        print(f"Error rejecting scholarship: {str(e)}")  # 添加错误日志
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/download_scholarship_proof/<int:file_id>')
@login_required
def download_scholarship_proof(file_id):
    record = ScholarshipApplication.query.get_or_404(file_id)
    
    if current_user.role != 'teacher' and current_user.id != record.user_id:
        abort(403)
    
    if record.attachments:  # 注意这里使用 attachments
        # 如果有多个附件，返回一个
        first_attachment = record.attachments[0] if isinstance(record.attachments, list) else record.attachments
        return send_from_directory(app.config['UPLOAD_FOLDER'], first_attachment)
    abort(404)

@app.route('/outstanding')
@login_required
def outstanding():
    if current_user.role == 'student':
        outstandings = Outstanding.query.filter_by(student_id=current_user.id).all()
    else:
        outstandings = Outstanding.query.all()
    return render_template('outstanding.html', outstandings=outstandings)

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('login'))

#Flask 的路由装饰器，将/submit_academic路径与submit_academic视图函数绑定，并指定该路径只接受 HTTP POST 请求。
@app.route('/submit_academic', methods=['POST'])
#Flask - Login 的装饰器，确保只有登录的用户才能访问该视图函数。如果用户未登录，Flask - Login 会自动将用户重定向到登录页面。
@login_required
def submit_academic():
    if current_user.role != 'student':
#用flash函数向用户显示一条错误消息，消息内容为 “只有学生可以提交成绩”，error是消息的类别，用于在前端页面以特定的样式显示错误消息。
        flash('只有学生可以提交成绩', 'error')
#将用户重定向到名为academic的视图函数对应的 URL
        return redirect(url_for('academic'))
    
    try:
        semester = request.form['semester']
        academic_score = float(request.form['academic_score'])
        
        if not (0 <= academic_score <= 4):
            flash('成绩必须在0-4之间', 'error')
            return redirect(url_for('academic'))
        
        # 处理文件上传（选填）
        proof_file = None
        if 'score_proof' in request.files:
#检查 POST 请求中是否包含名为score_proof的文件。
            file = request.files['score_proof']
#进一步检查文件是否存在且文件名不为空，确保用户确实选择了一个文件
            if file and file.filename != '':  # 只在用户选择了文件时处理
#调用allowed_file函数检查文件的格式是否允许上传
                if allowed_file(file.filename):
#使用secure_filename函数生成一个安全的文件名，防止文件名中包含可能导致安全问题的特殊字符
                    filename = secure_filename(file.filename)
#通过当前用户名、时间戳和安全文件名生成一个唯一的文件名，以避免文件名冲突
                    unique_filename = f"{current_user.username}_{int(time.time())}_{filename}"
#使用os.path.join函数将上传文件夹路径
                    file_path = os.path.join(UPLOAD_FOLDER, unique_filename)
                    file.save(file_path)
                    proof_file = unique_filename
                else:
                    flash('不支持的文件格式', 'error')
                    return redirect(url_for('academic'))
        
        # 创建新记录
        new_record = AcademicRecord(
            student_id=current_user.id,
            class_name=current_user.class_name,
            semester=semester,
            academic_score=academic_score,
            proof_file=proof_file,  # 可以为 None
            status='pending',
            submit_time=datetime.now()
        )
        
        db.session.add(new_record)
        db.session.commit()
        
        flash('成绩提交成功，等待审核', 'success')
        return redirect(url_for('academic'))
        
    except Exception as e:
        print(f"Error submitting academic score: {str(e)}")  # 调试信息
        flash('提交失败，请稍后重试', 'error')
        return redirect(url_for('academic'))

# 文件载路由
#定义了一个名为/download_proof/<int:file_id>的路由，其中<int:file_id>是一个动态参数，表示文件对应的记录 ID。该路由只接受 GET 请求
@app.route('/download_proof/<int:file_id>')
@login_required
def download_proof(file_id):
#使用AcademicRecord模型的query.get_or_404方法，根据传入的file_id获取对应的成绩记录。如果找不到对应的记录，会返回一个 HTTP 404 错误。
    record = AcademicRecord.query.get_or_404(file_id)
    
    # 查权限（只有文件所有者和教师可以查看）
    if current_user.role != 'teacher' and current_user.id != record.student_id:
        abort(403)
    
#检查成绩记录中是否有证明文件的文件名,使用 Flask 的send_from_directory函数，从指定的上传文件夹（UPLOAD_FOLDER）中发送指定的文件给用户，实现文件下载功能
    if record.proof_file:
        return send_from_directory(UPLOAD_FOLDER, record.proof_file)
    abort(404)

# 教师审核路由
@app.route('/approve_academic/<int:record_id>', methods=['POST'])
@login_required
def approve_academic(record_id):
    print(f"Approving record {record_id}")  # 添加调试信息
    try:
        if current_user.role != 'teacher':
            print("Not a teacher")  # 调试信息
            return jsonify({'success': False, 'message': '权限不足'}), 403
            
#使用AcademicRecord模型的query.get_or_404方法，根据传入的record_id获取对应的成绩记录。如果找不到对应的记录，会返回一个 HTTP 404 错误
        record = AcademicRecord.query.get_or_404(record_id)
        print(f"Found record: {record}")  # 调试信息
        
        # 检查是否是该教师的班级
        if record.class_name != current_user.class_name:
            print(f"Class mismatch: {record.class_name} != {current_user.class_name}")  # 调试信息
            return jsonify({'success': False, 'message': '不能审核其他班级的成绩'}), 403
        
        record.status = 'approved'
        record.update_time = datetime.now()  # 添加更新时间
        db.session.commit()
        print("Approval successful")  # 调试信息
        return jsonify({'success': True, 'message': '审核通过成功'})
    except Exception as e:
        print(f"Error: {str(e)}")  # 调试息
        db.session.rollback()
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/reject_academic/<int:record_id>', methods=['POST'])
@login_required
def reject_academic(record_id):
    print(f"Rejecting record {record_id}")  # 添加调试信息
    try:
        if current_user.role != 'teacher':
            print("Not a teacher")  # 调试信息
            return jsonify({'success': False, 'message': '权限不足'}), 403
            
        record = AcademicRecord.query.get_or_404(record_id)
        print(f"Found record: {record}")  # 调试信息
        
        # 检查是否是该教师的班级
        if record.class_name != current_user.class_name:
            print(f"Class mismatch: {record.class_name} != {current_user.class_name}")  # 调试信息
            return jsonify({'success': False, 'message': '不能审核其他班级的成绩'}), 403
        
        record.status = 'rejected'
        db.session.commit()
        print("Rejection successful")  # 调试信息
        return jsonify({'success': True, 'message': '驳回成功'})
    except Exception as e:
        print(f"Error: {str(e)}")  # 调试信息
        db.session.rollback()
        return jsonify({'success': False, 'message': str(e)}), 500

# 改提交路由中的计算逻辑
@app.route('/submit_moral', methods=['POST'])
@login_required
def submit_moral():
    if current_user.role != 'student':
        flash('只有学生可以提交成绩', 'error')
        return redirect(url_for('moral'))
    
    try:
        semester = request.form['semester']
        base_score = float(request.form['base_score'])
        bonus_items = []
        penalty_items = []
        
        # 验证基础分范围
        if not (0 <= base_score <= 100):
            flash('基础分必须在0-100之间', 'error')
            return redirect(url_for('moral'))
        
        # 处理加分项
#初始化一个空列表bonus_items，用于存储加分项的信息。
        bonus_item_list = request.form.getlist('bonus_items[]')
        bonus_score_list = request.form.getlist('bonus_scores[]')
        bonus_other_list = request.form.getlist('bonus_other[]')
        
        #使用zip函数将三个列表中的元素一一对应进行遍历。对于每一组对应的元素，如果加分项名称和分数都存在：
        #创建一个字典bonus_item，包含加分项名称和分数。
        #如果加分项名称为other，则将 “其他” 加分项的具体内容添加到字典中。
        #将这个字典添加到bonus_items列表中
        for item, score, other in zip(bonus_item_list, bonus_score_list, bonus_other_list):
            if item and score:
                bonus_item = {
                    'item': item,
                    'score': float(score)
                }
                if item == 'other':
                    bonus_item['other_content'] = other
                bonus_items.append(bonus_item)
        
        # 处理减分项
        penalty_item_list = request.form.getlist('penalty_items[]')
        penalty_score_list = request.form.getlist('penalty_scores[]')
        penalty_other_list = request.form.getlist('penalty_other[]')
        
        for item, score, other in zip(penalty_item_list, penalty_score_list, penalty_other_list):
            if item and score:
                penalty_item = {
                    'item': item,
                    'score': float(score)
                }
                if item == 'other':
                    penalty_item['other_content'] = other
                penalty_items.append(penalty_item)
        
        # 计算总分
        bonus_total = sum(item['score'] for item in bonus_items)
        penalty_total = sum(item['score'] for item in penalty_items)
        total_score = base_score + bonus_total - penalty_total
        
        # 确保总分不超过100分
        total_score = min(100, max(0, total_score))
        
        # 处理文件上传
        proof_file = None
        if 'proof_file' in request.files:
            file = request.files['proof_file']
            if file and file.filename != '' and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                unique_filename = f"moral_{current_user.username}_{int(time.time())}_{filename}"
                file_path = os.path.join(UPLOAD_FOLDER, unique_filename)
                file.save(file_path)
                proof_file = unique_filename
        
        # 创建新记录
        new_record = MoralRecord(
            student_id=current_user.id,
            class_name=current_user.class_name,
            semester=semester,
            base_score=base_score,
            bonus_items=bonus_items,
            penalty_items=penalty_items,
            total_score=total_score,
            proof_file=proof_file,
            status='pending',
            submit_time=datetime.now()
        )
        
        db.session.add(new_record)
        db.session.commit()
        
        flash('德育成绩提交成功，等待审核', 'success')
        return redirect(url_for('moral'))
        
    except Exception as e:
        print(f"Error submitting moral score: {str(e)}")  # 调试信息
        flash('提交失败，请稍后重试', 'error')
        return redirect(url_for('moral'))

# 添加德育成绩审核路由
@app.route('/approve_moral/<int:record_id>', methods=['POST'])
@login_required
def approve_moral(record_id):
    try:
        if current_user.role != 'teacher':
            return jsonify({'success': False, 'message': '权限不足'}), 403
            
        record = MoralRecord.query.get_or_404(record_id)
        
        if record.class_name != current_user.class_name:
            return jsonify({'success': False, 'message': '不能审核其他班级的成绩'}), 403
        
        record.status = 'approved'
        record.update_time = datetime.now()  # 添加更新时间
        db.session.commit()
        return jsonify({'success': True, 'message': '审核通过成功'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/reject_moral/<int:record_id>', methods=['POST'])
@login_required
def reject_moral(record_id):
    try:
        if current_user.role != 'teacher':
            return jsonify({'success': False, 'message': '权限不足'}), 403
            
        record = MoralRecord.query.get_or_404(record_id)
        
        if record.class_name != current_user.class_name:
            return jsonify({'success': False, 'message': '不能审核其他班级的成绩'}), 403
        
        record.status = 'rejected'
        db.session.commit()
        return jsonify({'success': True, 'message': '驳回成功'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'message': str(e)}), 500

# 添加德育成绩证明材料下载路由
@app.route('/download_moral_proof/<int:file_id>')
@login_required
def download_moral_proof(file_id):
    record = MoralRecord.query.get_or_404(file_id)
    
    if current_user.role != 'teacher' and current_user.id != record.student_id:
        abort(403)
    
    if record.proof_file:
        return send_from_directory(UPLOAD_FOLDER, record.proof_file)
    abort(404)

# 添加体育成绩提交路由
@app.route('/submit_physical', methods=['POST'])
@login_required
def submit_physical():
    if current_user.role != 'student':
        flash('只有学生可以提交成绩', 'error')
        return redirect(url_for('physical'))
    
    try:
        semester = request.form['semester']
        course_type = request.form['course_type']
        physical_score = float(request.form['physical_score'])
        
        # 验证课程型和成绩
        if course_type not in ['C1', 'C2','C3']:
            flash('无效的课程类型', 'error')
            return redirect(url_for('physical'))
        
        if course_type == 'C1' and physical_score != 60:
            flash('C1类型成绩必须为60分', 'error')
            return redirect(url_for('physical'))
        
        # 对于C2类型，验证体测结果
        test_result = None
        if course_type == 'C2':
            test_result = request.form.get('test_result')
            if test_result not in ['pass', 'fail', 'absent']:
                flash('无效的体测结果', 'error')
                return redirect(url_for('physical'))

            # 验证成绩是否与体测结果匹配
            expected_scores = {'pass': 100, 'fail': 40, 'absent': 0}
            if physical_score != expected_scores[test_result]:
                flash('成绩与体测结果不匹配', 'error')
                return redirect(url_for('physical'))
        if course_type == 'C3':
            physical_score = float(request.form['physical_score'])
            # 验证C3课程成绩是否在0 - 100之间
            if not (0 <= physical_score <= 100):
                flash('C3类型成绩必须在0到100之间', 'error')
                return redirect(url_for('physical'))

        # 处理文件上传（选填）
        proof_file = None
        if 'proof_file' in request.files:
            file = request.files['proof_file']
            if file and file.filename != '' and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                unique_filename = f"physical_{current_user.username}_{int(time.time())}_{filename}"
                file_path = os.path.join(UPLOAD_FOLDER, unique_filename)
                file.save(file_path)
                proof_file = unique_filename
        
        # 创建新记录
        new_record = PhysicalRecord(
            student_id=current_user.id,
            class_name=current_user.class_name,
            semester=semester,
            course_type=course_type,
            test_result=test_result,
            physical_score=physical_score,
            proof_file=proof_file,
            status='pending',
            submit_time=datetime.now()
        )
        
        db.session.add(new_record)
        db.session.commit()
        
        flash('体育成绩提交成功，等待审核', 'success')
        return redirect(url_for('physical'))
        
    except Exception as e:
        print(f"Error submitting physical score: {str(e)}")  # 调试信息
        flash('提交失败，请稍后重试', 'error')
        return redirect(url_for('physical'))

# 添加体育成绩审核路由
@app.route('/approve_physical/<int:record_id>', methods=['POST'])
@login_required
def approve_physical(record_id):
    print(f"Approving physical record {record_id}")  # 调试信息
    try:
        if current_user.role != 'teacher':
            print(f"User role is {current_user.role}")  # 调试信息
            return jsonify({'success': False, 'message': '权限不足'}), 403
            
        record = PhysicalRecord.query.get_or_404(record_id)
        print(f"Found record: {record}")  # 调试信息
        print(f"Record class: {record.class_name}, Teacher class: {current_user.class_name}")  # 调试信息
        
        if record.class_name != current_user.class_name:
            return jsonify({'success': False, 'message': '不能审核其他班级的成绩'}), 403
        
        record.status = 'approved'
        record.update_time = datetime.now()
        db.session.commit()
        print("Approval successful")  # 调试信息
        return jsonify({'success': True, 'message': '审核通过成功'})
    except Exception as e:
        print(f"Error in approve_physical: {str(e)}")  # 调试信息
        db.session.rollback()
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/reject_physical/<int:record_id>', methods=['POST'])
@login_required
def reject_physical(record_id):
    print(f"Rejecting physical record {record_id}")  # 调试信息
    try:
        if current_user.role != 'teacher':
            print(f"User role is {current_user.role}")  # 调试信息
            return jsonify({'success': False, 'message': '权限不足'}), 403
            
        record = PhysicalRecord.query.get_or_404(record_id)
        print(f"Found record: {record}")  # 调试信息
        print(f"Record class: {record.class_name}, Teacher class: {current_user.class_name}")  # 调试信息
        
        if record.class_name != current_user.class_name:
            return jsonify({'success': False, 'message': '不能审核其他班级的成绩'}), 403
        
        record.status = 'rejected'
        record.update_time = datetime.now()
        db.session.commit()
        print("Rejection successful")  # 调试信息
        return jsonify({'success': True, 'message': '驳回成功'})
    except Exception as e:
        print(f"Error in reject_physical: {str(e)}")  # 调试信息
        db.session.rollback()
        return jsonify({'success': False, 'message': str(e)}), 500

# 添加体育成绩证明材料下载路由
@app.route('/download_physical_proof/<int:file_id>')
@login_required
def download_physical_proof(file_id):
    record = PhysicalRecord.query.get_or_404(file_id)
    
    if current_user.role != 'teacher' and current_user.id != record.student_id:
        abort(403)
    
    if record.proof_file:
        return send_from_directory(UPLOAD_FOLDER, record.proof_file)
    abort(404)

# 初始化数据库
def init_db():
    with app.app_context():
        # 删除所有表并重新创建
        db.drop_all()
        db.create_all()
        
        # 创建测试用户
        if not User.query.filter_by(username='admin').first():
            # 管理员
            admin = User(
                username='admin',
                password='admin123',
                role='admin',
                real_name='管理员'
            )
            
            # 教师
            teacher1 = User(
                username='teacher1',
                password='teacher123',
                role='teacher',
                class_name='22级1班',
                real_name='张老师',
                academy_name='澜湄学院'
            )
            
            # 学生
            student1 = User(
                username='2022123',
                password='student123',
                role='student',
                class_name='22级1班',
                real_name='张三',
                academy_name='澜湄学院',
                major_name='信息管理与信息系统'
            )
            student2 = User(
                username='2022124',
                password='student123',
                role='student',
                class_name='22级1班',
                real_name='李四',
                academy_name='澜湄学院',
                major_name='信息管理与信息系统'
            )

            student3 = User(
                username='2022125',
                password='student123',
                role='student',
                class_name='22级1班',
                real_name='王五',
                academy_name='澜湄学院',
                major_name='信息管理与信息系统'
            )
            
            db.session.add(admin)
            db.session.add(teacher1)
            db.session.add(student1)
            db.session.add(student2)
            db.session.add(student3)
            db.session.commit()
            
            try:
                db.session.commit()
                print("初始化数据成功")
            except Exception as e:
                db.session.rollback()
                print(f"初始化数据失败: {str(e)}")

# 添加辅助函数来获取当前学期
def current_semester():
    now = datetime.now()
    year = now.year
    month = now.month
    
    if month >= 9:  # 9月及以后为第一学期
        return f"{year}-{year+1}-1"
    elif month >= 2:  # 2月到8月为二学期
        return f"{year-1}-{year}-2"
    else:  # 1月属于上一年的第一学期
        return f"{year-1}-{year}-1"

@app.route('/submit_outstanding', methods=['POST'])
@login_required
def submit_outstanding():
    if current_user.role != 'student':
        flash('只有学生可以提交申请', 'error')
        return redirect(url_for('outstanding'))
    
    try:
        # 获取表单数据
        category = request.form['category']
        semester = request.form['semester']
        reason = request.form['reason']
        
        # 处理文件上传（选填）
        proof_file = None
        if 'proof_file' in request.files:
            file = request.files['proof_file']
            if file and file.filename != '' and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                unique_filename = f"outstanding_{current_user.username}_{int(time.time())}_{filename}"
                file_path = os.path.join(UPLOAD_FOLDER, unique_filename)
                file.save(file_path)
                proof_file = unique_filename
        
        # 创建新记录
        new_record = Outstanding(
            student_id=current_user.id,
            category=category,
            semester=semester,
            reason=reason,
            proof_file=proof_file,
            status='pending',
            submit_time=datetime.now()
        )
        
        db.session.add(new_record)
        db.session.commit()
        
        flash('推优申请提交成功，等待审核', 'success')
        return redirect(url_for('outstanding'))
        
    except Exception as e:
        print(f"Error submitting outstanding application: {str(e)}")
        flash('提交失败，请稍后重试', 'error')
        return redirect(url_for('outstanding'))

# 在每个路由之前添加上下文处理器
@app.context_processor
def utility_processor():
    if not current_user.is_authenticated or current_user.role != 'teacher':
        return {}
    
    # 取该教师班级的所有待审核记录数量
    academic_pending = AcademicRecord.query.join(User).filter(
        User.class_name == current_user.class_name,
        AcademicRecord.status == 'pending'
    ).count()
    
    moral_pending = MoralRecord.query.join(User).filter(
        User.class_name == current_user.class_name,
        MoralRecord.status == 'pending'
    ).count()
    
    physical_pending = PhysicalRecord.query.join(User).filter(
        User.class_name == current_user.class_name,
        PhysicalRecord.status == 'pending'
    ).count()
    
    ability_pending = AbilityRecord.query.join(User).filter(
        User.class_name == current_user.class_name,
        AbilityRecord.status == 'pending'
    ).count()
    
    labor_pending = LaborRecord.query.join(User).filter(
        User.class_name == current_user.class_name,
        LaborRecord.status == 'pending'
    ).count()
    
    scholarship_pending = Scholarship.query.join(User).filter(
        User.class_name == current_user.class_name,
        Scholarship.status == 'pending'
    ).count()
    
    outstanding_pending = Outstanding.query.join(User).filter(
        User.class_name == current_user.class_name,
        Outstanding.status == 'pending'
    ).count()
    
    # 计算总的待审核数量
    pending_count = (
        academic_pending + 
        moral_pending + 
        physical_pending + 
        ability_pending + 
        labor_pending + 
        scholarship_pending + 
        outstanding_pending
    )
    
    return {
        'pending_count': pending_count,
        'academic_pending': academic_pending,
        'moral_pending': moral_pending,
        'physical_pending': physical_pending,
        'ability_pending': ability_pending,
        'labor_pending': labor_pending,
        'scholarship_pending': scholarship_pending,
        'outstanding_pending': outstanding_pending
    }

# 添加系统管理相关路由
@app.route('/permission')
@login_required
def permission():
    return render_template('permission.html', title='权限管理')

@app.route('/users')
@login_required
def users():
    return render_template('users.html', title='用户管理')

@app.route('/profile')
@login_required
def profile():
    return render_template('profile.html', title='个人中心')

@app.route('/maintenance')
@login_required
def maintenance():
    return render_template('maintenance.html', title='系统维护')

@app.route('/rules')
@login_required
def rules():
    return render_template('rules.html', title='测评规则标准管理')

# 修改静态文件路由
@app.route('/static/<path:filename>')
def static_files(filename):
    try:
        # 设置正确的 MIME 类型
        mimetype = None
        if filename.endswith('.pdf'):
            mimetype = 'application/pdf'
        
        # 使用 send_from_directory 函数发送文件
        return send_from_directory(
#通过 os.path.join 函数拼接应用的根路径（app.root_path）和 static 目录名，得到静态文件所在的目录路径
            os.path.join(app.root_path, 'static'),
            filename,
            mimetype=mimetype,
            as_attachment=True  # 这会强制浏览器下载文件而不是在线显示
        )
    except Exception as e:
        print(f"Error serving static file: {str(e)}")  # 调试信息
        abort(404)

# 确保在应用启动时创建 static 目录
def ensure_static_dir():
    #通过 os.path.join 函数拼接应用的根路径和 static 目录名，得到静态文件目录的完整路径
    static_dir = os.path.join(app.root_path, 'static')
    if not os.path.exists(static_dir):
        os.makedirs(static_dir)
        print(f"Created static directory at {static_dir}")

# 在应用启动时调用
#上下文管理器，用于创建一个应用上下文
with app.app_context():
#在应用上下文内调用 ensure_static_dir 函数，确保在应用启动时静态文件目录存在
    ensure_static_dir()

# 添加违纪违规管理相关路由
@app.route('/personal_violation')
@login_required
def personal_violation():
    return render_template('personal_violation.html', title='个人违规违纪记录')

@app.route('/all_violations')
@login_required
def all_violations():
    return render_template('all_violations.html', title='全院违规违纪记录')

# 确保添加文件上传配置
app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16MB max-limit

@app.route('/export_evaluation')
@login_required
def export_evaluation():
    try:
        if current_user.role == 'student':
            # 学生导出自己的记录
            evaluations = Evaluation.query.filter_by(
                student_id=current_user.id
            ).order_by(
                Evaluation.semester.desc()
            ).all()
            
            student = User.query.get(current_user.id)
            students_data = [(student, evaluations)]
            
        elif current_user.role == 'teacher':
            # 教师导出本班级所有学生的记录
            students = User.query.filter_by(
                class_name=current_user.class_name,
                role='student'
            ).all()
            
            # 获取所有评定记录并按总分排序
            all_evaluations = []
            for student in students:
                evaluations = Evaluation.query.filter_by(
                    student_id=student.id
                ).all()
                for eval in evaluations:
                    all_evaluations.append((student, eval))
            
            # sort方法按总分从高到低排序
            all_evaluations.sort(key=lambda x: x[1].total_score or 0, reverse=True)
            students_data = all_evaluations
            
        else:
            flash('没有导出权限', 'error')
            return redirect(url_for('dashboard'))
        
        # 创建工作簿和工作表
        wb = Workbook()
        ws = wb.active
        ws.title = "综合评定记录"
        
        # 添加表头
        headers = ['学号', '姓名', '学期', '学业成绩', '德育素质', '体育素质', '能力素质', '劳育素质', '总分']
        ws.append(headers)
        
        # 添加数据
        #如果是学生，遍历students_data中的每个评定记录，将学生信息和评定记录的各项数据组成一行，添加到工作表中。
        #如果是教师，直接遍历排序后的students_data，将学生信息和评定记录的各项数据组成一行，添加到工作表中
        if current_user.role == 'student':
            # 学生的数据保持原有格式
            for student, evaluations in students_data:
                for eval in evaluations:
                    row = [
                        student.username,
                        student.real_name,
                        eval.semester,
                        eval.academic_score or 0,
                        eval.moral_score or 0,
                        eval.physical_score or 0,
                        eval.ability_score or 0,
                        eval.labor_score or 0,
                        eval.total_score or 0
                    ]
                    ws.append(row)
        else:
            # 教师的数据直接使用排序后的列表
            for student, eval in students_data:
                row = [
                    student.username,
                    student.real_name,
                    eval.semester,
                    eval.academic_score or 0,
                    eval.moral_score or 0,
                    eval.physical_score or 0,
                    eval.ability_score or 0,
                    eval.labor_score or 0,
                    eval.total_score or 0
                ]
                ws.append(row)
        
        # 调整列宽
        for column in ws.columns:
            max_length = 0
            column = list(column)
            for cell in column:
                try:
                    if len(str(cell.value)) > max_length:
                        max_length = len(str(cell.value))
                except:
                    pass
            adjusted_width = (max_length + 2)
            ws.column_dimensions[column[0].column_letter].width = adjusted_width
        
        # 保存到内存中
        excel_file = BytesIO()
        wb.save(excel_file)
        excel_file.seek(0)
        
        # 生成文件名
        if current_user.role == 'student':
            filename = f"综合评定记录_{current_user.username}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
        else:
            filename = f"综合评定记录_{current_user.class_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
        
        return send_file(
            excel_file,
            mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            as_attachment=True,
            download_name=filename
        )
        
    except Exception as e:
        print(f"Error exporting evaluation: {str(e)}")
        flash('导出失败，请稍后重试', 'error')
        return redirect(url_for('dashboard'))

if __name__ == '__main__':
    init_db()
    app.run(debug=True, port=6789)